Method overriding

Method overriding, in object oriented programming, is a language feature that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its superclasses or parent classes. The implementation in the subclass overrides (replaces) the implementation in the superclass by providing a method that has same name, same parameters or signature, and same return type as the method in the parent class.[1] The version of a method that is executed will be determined by the object that is used to invoke it. If an object of a parent class is used to invoke the method, then the version in the parent class will be executed, but if an object of the subclass is used to invoke the method, then the version in the child class will be executed.[2] Some languages allow a programmer to prevent a method from being overridden.

Contents

Language-specific examples

C#

C# does support method overriding, but only if explicitly requested with the keywords override and virtual.

class Animal {
  public          String name;
  // Methods
  public          void   drink();
  public virtual  void   eat();
  public          void   go();
}
 
class Cat : Animal {
  public new      String name;
  // Methods
  public          void   drink();  // warning: hides inherited drink(). Use new
  public override void   eat();    // overwrites inherited eat().
  public new      void   go();     // hides inherited go().
}

To make method overriding to occur, the signatures must be identical (with same visibility). In C#, not only class methods can be overridden, but indexers and properties as well. As they are only methods of the class and not of the class instances, static methods cannot be overridden.

In addition to requesting keywords to make method overriding possible, C# gives the possibility of hiding an inherited property or method. This is done by using the same signature of a property or method and adding the keyword new in front of it.[3]

In the above example, hiding causes the following:

Cat cat = new Cat();
 
cat.name =;             // accesses Cat.name
cat.eat();                // calls Cat.eat()
cat.go();                 // calls Cat.go()
((Animal)cat).name =;   // accesses Animal.name!
((Animal)cat).eat();      // calls Animal.eat()!
((Animal)cat).go();       // calls Animal.go()!

C++

C++ does not have the keyword super that a subclass can use in Java to invoke a superclass version of a method that it wants to override. Instead, the name of the parent or base class is used followed by the scope resolution operator. For example, the following code presents two classes, the base class Rectangle, and the derived class Box. Box overrides the Rectangle class's print() method, so as also to print its height.[4]

#include <iostream>
 
class Rectangle {
public:
    explicit Rectangle(double l, double w) : length(l), width(w) {}
    virtual void print() const;
 
private:
    double length;
    double width;
};
 
void Rectangle::print() const { // print() method of base class
   std::cout << "Length = " << this->length << "; Width = " << this->width;
}
 
class Box : public Rectangle {
public:
    explicit Box(double l, double w, double h) : Rectangle(l, w), height(h) {}
    virtual void print() const; // virtual is optional here, but it is a good practice to remind it to the developer
 
private:
    double height;
};
 
void Box::print() const { // print() method of derived class
   Rectangle::print();  // Invoke parent print() method.
   std::cout << "; Height= " << this->height;
}

The method print() in class Box, by invoking the parent version of method print(), is also able to output the private variables length and width of the base class. Otherwise, these variables are inaccessible to Box.

The following statements will instantiate objects of type Rectangle and Box, and call their respective print() methods:

int main(int argc, char** argv) {
   Rectangle rectangle(5.0, 3.0);   rectangle.print();
   // outputs:
   // Length = 5.0; Width = 3.0
 
   Box box(6.0, 5.0, 4.0);
   // the pointer to the most overridden method in the vtable in on Box::print
   box.print(); // but this call does not illustrate overriding
   static_cast<Rectangle&>(box).print(); // this one does
   // outputs:
   // Length = 5.0; Width = 3.0; Height= 4
}

Eiffel

In Eiffel, feature redefinition is analogous to method overriding in C++ and Java. Redefinition is one of three forms of feature adaptation classified as redeclaration. Redeclaration also covers effecting, in which an implementation is provided for a feature which was deferred (abstract) in the parent class, and undefinition, in which a feature that was effective (concrete) in the parent becomes deferred again in the heir class. When a feature is redefined, the feature name is kept by the heir class, but properties of the feature such as its signature, contract (respecting restrictions for preconditions and postconditions), and/or implementation will be different in the heir. If the original feature in the parent class, called the heir feature's precursor, is effective, then the redefined feature in the heir will be effective. If the precursor is deferred, the feature in the heir will be deferred.[5]

The intent to redefine a feature, as message in the example below, must be explicitly declared in the inherit clause of the heir class.

class
    THOUGHT
feature
    message
            -- Display thought message
        do
            print ("I feel like I am diagonally parked in a parallel universe.%N")
        end
end
 
class
    ADVICE
inherit
    THOUGHT
        redefine
            message
        end
feature
    message
            -- <Precursor>
        do
            print ("Warning: Dates in calendar are closer than they appear.%N")
        end
end

In class ADVICE the feature message is given an implementation that differs from that of its precursor in class THOUGHT.

Consider a class which uses instances for both THOUGHT and ADVICE:

class
    APPLICATION
create
    make
feature 
    make
            -- Run application.
        do
            (create {THOUGHT}).message;
            (create {ADVICE}).message
        end
end

When instantiated, class APPLICATION produces the following output:

I feel like I am diagonally parked in a parallel universe.
Warning: Dates in calendar are closer than they appear.

Within a redefined feature, access to the feature's precursor can be gained by using the language keyword Precursor. Assume the implementation of {ADVICE}.message is altered as follows:

    message
            -- <Precursor>
        do
            print ("Warning: Dates in calendar are closer than they appear.%N")
            Precursor
        end

Invocation of the feature now includes the execution of {THOUGHT}.message, and produces the following output:

Warning: Dates in calendar are closer than they appear.
I feel like I am diagonally parked in a parallel universe.

Java

In Java, when a subclass contains a method that overrides a method of the superclass, it can also invoke the superclass method by using the keyword super (Lewis & Loftus, 2006).[2] Example:

public class Thought {
    public void message() {
        System.out.println("I feel like I am diagonally parked in a parallel universe.");
    }
}
 
public class Advice extends Thought {
    @Override  // @Override annotation in Java 5 is optional but helpful.
    public void message() {
        System.out.println("Warning: Dates in calendar are closer than they appear.");
    }
}

Class Thought represents the superclass and implements a method call message(). The subclass called Advice inherits every method that could be in the Thought class. However, class Advice overrides the method message(), replacing its functionality from Thought.

Thought parking = new Thought();
parking.message();  // Prints "I feel like I am diagonally parked in a parallel universe."
 
Thought dates = new Advice();  // Polymorphism
dates.message();  // Prints "Warning: Dates in calendar are closer than they appear."

The super reference can be used to call the superclass's version of the method from the subclass. For example, this variation prints out both messages when the subclass method is called:

public class Advice extends Thought {
      @Override
      public void message() {
          System.out.println("Warning: Dates in calendar are closer than they appear.");
          super.message();  // Invoke parent's version of method.
      }
  }

There are methods that a subclass cannot override. For example, in Java, a method that is declared final in the super class cannot be overridden. Methods that are declared private or static cannot be overridden either because they are implicitly final. It is also impossible for a class that is declared final to become a super class.[6]

Python

In Python, when a subclass contains a method that overrides a method of the superclass, you can also call the superclass method by calling Superclass.method instead of self.method]. Example:

class Thought(object):
    def __init__(self):
        pass
    def message():
         print "I feel like I am diagonally parked in a parallel universe."
 
class Advice(Thought):
    def __init__(self):
         Thought.__init__(self)
    def message():
         print "Warning: Dates in calendar are closer than they appear"
         Thought.message(self)

Notes

  1. ^ Flanagan 2002, p. 107
  2. ^ a b Lewis & Loftus 2006, p.454
  3. ^ Mössenböck, Hanspeter (2002-03-25). "Advanced C#: Overriding of Methods". http://ssw.jku.at/Teaching/Lectures/CSharp/Tutorial/: Institut für Systemsoftware, Johannes Kepler Universität Linz, Fachbereich Informatik. pp. 6–8. http://ssw.jku.at/Teaching/Lectures/CSharp/Tutorial/Part2.pdf. Retrieved 2011-08-02. 
  4. ^ Malik 2006, p. 676
  5. ^ Meyer 2009, page 572-575
  6. ^ Deitel & Deitel 2001, p.474

See also

References

External links